
#include <BIcon>
#include <BStyle>
#include <BLabel>
#include <BPainter>
#include <BButton>
#include <BGroupBox>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BSonDocument>
#include <BCheckBox>
#include <BMessageBox>
#include <BFileDialog>
#include <BFile>
#include <BBuffer>

#include "Series.h"
#include "MainWindow.h"

BColor HexstrToColor(const BString& text)
{
	BColor color;
	if (text[0] == '#')
	{
		const char* cstr = text.cstr() + 1;
		int size = text.size() - 1;
		if (size == 8)
		{
			color.r() = bHexToInt(cstr + 0, 2);
			color.g() = bHexToInt(cstr + 2, 2);
			color.b() = bHexToInt(cstr + 4, 2);
			color.a() = bHexToInt(cstr + 6, 2);
		}
		if (size == 6)
		{
			color.r() = bHexToInt(cstr + 0, 2);
			color.g() = bHexToInt(cstr + 2, 2);
			color.b() = bHexToInt(cstr + 4, 2);
			color.a() = 255;
		}
	}
	return color;
}
BString HexstrFromColor(const BColor& color)
{
	BString text('#');
	char temp[4];
	bByteToHex(temp, color.r());	text << temp;
	bByteToHex(temp, color.g());	text << temp;
	bByteToHex(temp, color.b());	text << temp;
	bByteToHex(temp, color.a());	text << temp;
	return text;
}

MainWindow::MainWindow(BWidget* parent) : BMainWindow(parent)
{
	this->setTitle("Variable Monitor");
	this->setTitle("Oscillo Scope");

	_fileListWidget = new BListWidget("Files");

	BVBoxLayout* rightLayout = new BVBoxLayout();
	{
		_markChartView = new MarkChartView();
		_markChartView->setTimeScale(BReal(0.01));
		{
			_valueUnitComboBox = new BComboBox(_markChartView);
			_valueUnitComboBox->addItem("m", (BReal)0.000001);
			_valueUnitComboBox->addItem("mm", (BReal)0.001);
			_valueUnitComboBox->addItem("um", (BReal)1);
			_valueUnitComboBox->setText("mm");
			_valueUnitComboBox->setArrowVisible(false);
		}

		BHBoxLayout* bottomLayout = new BHBoxLayout();
		{
			_cleanButton = new BButton("clean");
			_loadButton = new BButton("Load");
			_saveButton = new BButton("Save");
			bottomLayout->addSpring();
			bottomLayout->addWidget(_cleanButton);
			bottomLayout->addWidget(_loadButton);
			bottomLayout->addWidget(_saveButton);
		}

		rightLayout->addWidget(_markChartView);
		rightLayout->addLayout(bottomLayout, 0);
	}

	BHBoxLayout* hlayout = new BHBoxLayout(this);
	hlayout->setSplitable(true);
	hlayout->setSpacing(5);
	hlayout->addWidget(_fileListWidget, 1);
	hlayout->addLayout(rightLayout, 5);

	connect(_fileListWidget, Signal_RightClicked, &MainWindow::slotFileListWidgetRightClicked);
	connect(_fileListWidget, Signal_Framed, &MainWindow::slotFileListWidgetFramed);
	connect(_fileListWidget, Signal_KeyPress, &MainWindow::slotFileListWidgetKeyPress);
	connect(_fileListWidget, Signal_SelectionChanged, &MainWindow::slotFileListWidgetSelectionChanged);

	connect(_markChartView, Signal_Resized, &MainWindow::slotChartViewResized);
	connect(_valueUnitComboBox, Signal_ValueChanged, &MainWindow::slotValueUnitChanged);
	connect(_cleanButton, Signal_Clicked, &MainWindow::slotCleanButtonClicked);
	connect(_loadButton, Signal_Clicked, &MainWindow::slotLoadButtonClicked);
	connect(_saveButton, Signal_Clicked, &MainWindow::slotSaveButtonClicked);

}
MainWindow::~MainWindow()
{

}

void MainWindow::slotFileListWidgetRightClicked(BListWidget* listWidget, const BValue& value)
{
	const BPoint& point = value;
	if (BListItem* item = listWidget->itemAt(point))
	{
		if (BAction* action = item->asset())
		{

		}
	}
}
void MainWindow::slotFileListWidgetFramed(BListWidget* listWidget, const BValue& value)
{
	BPainter painter(listWidget);
	BRect crect = listWidget->centerRect();
	for (int i = 0; i < listWidget->itemCount(); i++)
	{
		BListItem* item = listWidget->item(i);
	}
}
void MainWindow::slotFileListWidgetKeyPress(BListWidget* listWidget, const BValue& value)
{
	if (BListItem* item = listWidget->selectedItem())
	{
		if (Series* series = item->asset())
		{
			_markChartView->removeSeries(series);
		}
		else
		{
		}
		listWidget->removeItem(item);
	}
}
void MainWindow::slotFileListWidgetSelectionChanged(BListWidget* listWidget, const BValue& value)
{
}

void MainWindow::slotChartViewResized(BObject* object, const BValue& value)
{
	BRect rect = _markChartView->valueLabelRect();
	rect.top() = _markChartView->rect(Part_Top).bottom();
	rect.bottom() = _markChartView->rect(Part_Center).top();
	BSize hsize = _valueUnitComboBox->sizeHint();
	rect = rect.align(Align_RightCenter, hsize);
	rect.move(hsize.width(), 0);
	_valueUnitComboBox->setPos(rect.pos());
	_valueUnitComboBox->setSize(hsize);
}
void MainWindow::slotValueUnitChanged(BObject* object, const BValue& value)
{
	BReal unit = _valueUnitComboBox->value();
	for (int i = 0; i < _dataBuffer.size(); i += _markChartView->seriesCount())
	{
		int* data = _dataBuffer.data(i);
		for (int c = 0; c < _markChartView->seriesCount(); c++)
		{
			Series* series = _markChartView->series(c);
			series->replaceValue(i, data[c] * unit);
		}
	}

	if (_markChartView->freshRanges())
	{
		BRealRange valueRange = _markChartView->valueRange();
		valueRange.scale(valueRange.mid(), 1.2);
		_markChartView->setValueRange(valueRange);

		BRealRange keyRange = _markChartView->timeRange();
		keyRange.min() -= keyRange.size() / 10;
		keyRange.max() += keyRange.size() / 10;
		_markChartView->setTimeRange(keyRange);
	}

	_markChartView->scrollTo(Part_Right);
	_markChartView->fullView();
	_markChartView->fresh();
}
void MainWindow::slotCleanButtonClicked(BObject* object, const BValue& value)
{
	if (_markChartView->name().size())
	{
		_markChartView->setName(BString());
		_markChartView->clearSeries();
	}
	else
	{
		for (int i = 0; i < _markChartView->seriesCount(); i++)
		{
			Series* series = _markChartView->series(i);
			series->clearValue();
		}
	}
	_markChartView->clearMasks();
	_dataBuffer.clear();
}
void MainWindow::slotLoadButtonClicked(BObject* object, const BValue& value)
{
	const BString& fileName = BFileDialog::OpenFile(this, "Open Record Data", "", "*.csv");
	_markChartView->clearSeries();
	_markChartView->setName(fileName.name());

	BString text;
	BFile::Load(fileName, text);
	int pos = 0;
	BString lineText;
	BStringArray words;

	pos = text.line(lineText, pos);
	lineText.trimmed();
	int count = lineText.split(words, ',');
	for (int i = 0; i < count; i++)
	{
		Series* series = new Series(words[i]);
		_markChartView->addSeries(series);
	}

	pos = text.line(lineText, pos);
	lineText.trimmed();
	count = lineText.split(words, ',');
	for (int i = 0; i < count; i++)
	{
		BColor color = HexstrToColor(words[i]);
		Series* series = _markChartView->series(i);
		series->setLineColor(color);
	}

	BReal unit = _valueUnitComboBox->value();
	BReal time = 0;
	while (pos < text.size())
	{
		pos = text.line(lineText, pos);
		lineText.trimmed();
		int count = lineText.split(words, ',');
		for (int c = 0; c < words.size(); c++)
		{
			int v = words[c].toInt();
			_dataBuffer.append(v);
			Series* series = _markChartView->series(c);
			series->insertValue(time, BReal(v * unit));
		}
		time += 1;
	}

	if (_markChartView->freshRanges())
	{
		BRealRange valueRange = _markChartView->valueRange();
		valueRange.scale(valueRange.mid(), 1.2);
		_markChartView->setValueRange(valueRange);

		BRealRange keyRange = _markChartView->timeRange();
		keyRange.min() -= keyRange.size() / 10;
		keyRange.max() += keyRange.size() / 10;
		_markChartView->setTimeRange(keyRange);
	}

	_markChartView->scrollTo(Part_Right);
	_markChartView->fullView();
	_markChartView->fresh();

}
void MainWindow::slotSaveButtonClicked(BObject* object, const BValue& value)
{
	if (int count = _markChartView->seriesCount())
	{
		BString fileName = BFileDialog::SaveFile(this, "Save file","", "*.csv");
		if (fileName.size())
		{
			BBuffer buffer;
			buffer.setMode(IO_Text);
			BString str;
			for (int i = 0; i < count; i++)
			{
				Series* series = _markChartView->series(i);
				str << series->name() << ',';
			}
			str -= ',';
			str << "\n";
			buffer.write(str);

			str.reset();
			for (int i = 0; i < count; i++)
			{
				Series* series = _markChartView->series(i);
				str << HexstrFromColor(series->lineColor()) << ',';
			}
			str -= ',';
			str << "\n";
			buffer.write(str);

			BReal unit = _valueUnitComboBox->value();
			for (int i = 0; i < _dataBuffer.size(); i += count)
			{
				int* data = _dataBuffer.data(i);
				str.reset();
				for (int c = 0; c < count; c++)
				{
					str << data[c] << ',';
				}
				str -= ',';
				str << "\n";
				buffer.write(str);
			}
			BFile::Save(fileName, buffer);
		}
	}
}

void MainWindow::updateEvent(const BEvent& event)
{
	BReal now = bTime();
	static BReal tick = 0;
	if (now - tick > 1)
	{

	}
}

void MainWindow::showEvent(const BEvent& event)
{
	BMainWindow::showEvent(event);
}
void MainWindow::hideEvent(const BEvent& event)
{
	BMainWindow::hideEvent(event);
}

void MainWindow::styleEvent(const BEvent& event)
{
	BMainWindow::styleEvent(event);
	const BStyle* style = event.value();

	_cleanButton->setIcon(style->icon("clean"));
	_loadButton->setIcon(style->icon("load"));
	_saveButton->setIcon(style->icon("save"));

	_cleanButton->setTips(style->text("tips-clear"));
	_loadButton->setTips(style->text("tips-load"));
	_saveButton->setTips(style->text("tips-save"));

}